import copy

from trees import MagicMap

class Reference:
  def __init__(self, root, path):
    self.root=root
    self.path=path

    self.deref()

  def deref(self):
    if len(self.path)==0:
      return self.root
    else:
      return self.root.resolve(self.path)

  def keys(self):
    return self.deref().keys()

  def __getitem__(self, key):
    return self.chain([key])

  def __setitem__(self, key, value):
    self.deref()[key]=value

  def resolve(self, p):
    if len(p)==0:
      return self.deref()
    elif len(self.path)==0:
      return self.root.resolve(self.path)
    else:
      obj=self.root.resolve(self.path)
      return obj.resolve(p)

  def lookup(self, key, debug=False):
    if debug:
      print 'Ref looking up', key
    if debug:
      print 'First try'
    try:
      value=self[key]
      if debug:
        print 'Got it', value
      return value
    except:
      if debug:
        print 'Failed, trying with index=0'
      index=0
      while index<=len(self.path):
        path=self.path[:len(self.path)-index]
        if debug:
          print 'Path:', path
        ref=Reference(self.root, path)
        try:
          value=ref[key]
          if debug:
            print 'Got it', value
          return value
        except:
          print 'Failed, trying with', index+1
          index=index+1

  def resolveFrom(self, keys, index):
    if len(keys)==index+1:
      return self.get(keys[index])
    else:
      key=keys[index]
      entry=self.map[key]
      map=entry.value
      return map.resolveFrom(keys, index+1)

  def chain(self, p):
    return Reference(self.root, self.path+p)

  def clone(self):
    return Reference(self.root.clone(), self.path)

  def __str__(self):
    return "<Reference(%s)%s>" % (self.root.__hash__(), str(self.path))

  def __repr__(self):
    return "<Reference(%s)%s>" % (self.root.__hash__(), str(self.path))

  def expand(self):
    value=self.deref()
    if value.__class__==MagicMap:
      sval=value.keys()
    else:
      sval="<skip>"
    if len(self.path)==0:
      return "%s" % (sval)
    else:
      return "%s -> %s" % (sval, Reference(self.root, self.path[:-1]).expand())

class Context:
  def __init__(self, ref, locals=None):
    self.ref=ref
    self.locals=locals
    if not self.locals:
      self.locals=MagicMap()

    assert self.ref==None or self.ref.__class__==Reference
    assert self.locals.__class__==MagicMap

  def getRef(self, key):
    try:
      value=self.locals[key]
      return value
    except Exception, e:
      if self.ref:
        return self.ref.lookup(key)
      else:
        return None

  def __getitem__(self, key):
    print('get:', key, self.locals.keys())
    try:
      value=self.locals[key]
      return value
    except Exception, e:
      if self.ref:
        return self.ref.lookup(key).deref()
      else:
        return None

  def __setitem__(self, key, value):
    self.locals[key]=value

  def __str__(self):
    if self.ref:
      return "%s --> %s" % (self.locals, self.ref.expand())
    else:
      return "%s" % (self.locals)

  def __repr__(self):
    return self.__str__()
